#import "GraphicsUtilities.h"

// Shared instance of GraphicsUtilities
static GraphicsUtilities* sharedUtilities = nil;
// The cached view of the prompt message
static UIView* promptView = nil;
// The cached prompt message
static UILabel* promptLabel = nil;
// The progress view for the activity indicator
static UIAlertView* progressView = nil;
// The activity indicator in the progress view
static UIActivityIndicatorView* progressIndicator = nil;
// Tracker for custom prompt height
static CGFloat promptHeight = -1;

/**
 * A GraphicsUtilities is an object representing the helper
 * graphics methods created for convenience sake.
 *
 * @author      James Lin
 * @version     2.0.2
 * @since       1.0.6
 */
@implementation GraphicsUtilities

/**
 * Retrieve the shared instance of the graphics utilities.
 *
 * @return  the shared instance of GraphicsUtilities
 */
+ (GraphicsUtilities*)sharedUtilities {
	@synchronized(self) {
		if (sharedUtilities == nil) {
			sharedUtilities = [[GraphicsUtilities alloc] init];
		}
		return sharedUtilities;
	}
}

/**
 * Allocate the graphics utilities.
 *
 * @return  the newly allocated shared instance of GraphicsUtilities
 */
+ (id) alloc {
	@synchronized(self) {
		sharedUtilities = [super alloc];
		return sharedUtilities;
	}
}

/**
 * Retrieve a copy of the graphics utilities.
 *
 * @return  the shared instance of GraphicsUtilities
 */
+ (id) copy {
	@synchronized(self) {
		return sharedUtilities;
	}
}

/**
 * Display an overlay prompt with given message.
 *
 * Animates downwards from the top of the screen.
 * Supplying a colour is optional and will produce a
 * default dark red background for the prompt.
 *
 * @param message  the message to show on the prompt
 * @param view     the view in which this prompt is shown
 * @param color    color of the background of the prompt, if supplied;
 *                 dark red, if nil.
 */
+ (void)showPrompt:(NSString*)message 
			inView:(UIView*)view 
		 withColor:(UIColor*)color {
	if (promptView) {
		[promptView release];
	}
	// Create the view to contain the prompt
	promptView = [[UIView alloc] initWithFrame:CGRectMake(0, -MSG_PROMPT_HEIGHT, 
														  VIEW_WIDTH, 
														  MSG_PROMPT_HEIGHT)];
	promptView.backgroundColor = color ? color : [UIColor colorWithRed:0.6 
																 green:0.05 
																  blue:0.05 
																 alpha:0.8];
	if (promptLabel) {
		[promptLabel release];
	}
	// Create the prompt label
	promptLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, VIEW_WIDTH, 
															MSG_PROMPT_HEIGHT)];
	promptLabel.text = message;
	promptLabel.font = [UIFont boldSystemFontOfSize:12.0];
	promptLabel.textColor = [UIColor whiteColor];
	promptLabel.textAlignment = UITextAlignmentCenter;
	promptLabel.backgroundColor = [UIColor clearColor];
	promptHeight = -1;
	
	// Add the prompt to the given view
	[promptView addSubview:promptLabel];
	[view addSubview:promptView];
	
	// Animate the prompt downwards into visibility
	[UIView beginAnimations:nil context:@"promptView"];
	[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
	[UIView setAnimationDuration:0.3];
	[promptView setFrame:CGRectMake(0, 0, VIEW_WIDTH, 
									MSG_PROMPT_HEIGHT)];
	[UIView commitAnimations];
}

/**
 * Display an overlay prompt with given message and custom height.
 *
 * Animates downwards from the top of the screen.
 * Supplying a colour is optional and will produce a
 * default dark red background for the prompt.
 *
 * @param message  the message to show on the prompt
 * @param view     the view in which this prompt is shown
 * @param color    color of the background of the prompt, if supplied;
 *                 dark red, if nil.
 * @param height   height of the prompt
 */
+ (void)showPrompt:(NSString*)message 
			inView:(UIView*)view 
		 withColor:(UIColor*)color 
		 andHeight:(CGFloat)height {
	if (promptView && promptLabel) {
		[GraphicsUtilities hidePromptAnimated:YES];
		//[promptView release];
	}
	
	// Create the view to contain the prompt
	promptView = [[UIView alloc] initWithFrame:CGRectMake(0, -height, 
														  VIEW_WIDTH, 
														  height)];
	promptView.backgroundColor = color ? color : [UIColor colorWithRed:0.6 
																 green:0.05 
																  blue:0.05 
																 alpha:0.8];
	if (promptLabel) {
		[promptLabel release];
	}
	// Create the prompt label
	promptLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 
															VIEW_WIDTH, 
															height)];
	promptLabel.text = message;
	promptLabel.font = [UIFont boldSystemFontOfSize:14.0];
	promptLabel.textColor = [UIColor whiteColor];
	promptLabel.textAlignment = UITextAlignmentCenter;
	promptLabel.backgroundColor = [UIColor clearColor];
	promptHeight = height;
	
	// Add the prompt to the given view
	[promptView addSubview:promptLabel];
	[view addSubview:promptView];
	
	// Animate the prompt downwards into visibility
	[UIView beginAnimations:nil context:@"promptView"];
	[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
	[UIView setAnimationDuration:0.3];
	[promptView setFrame:CGRectMake(0, 0, VIEW_WIDTH, height)];
	[UIView commitAnimations];
}

/**
 * Change the message of the prompt.
 *
 * Only effective after calling showPrompt:inView:.
 * Does nothing if no prompt shown.
 *
 * @param message  the new message to which to change the prompt
 */
+ (void)changePrompt:(NSString*)message {
	if (promptView && promptLabel) {
		promptLabel.text = message;
	}
}

/**
 * Hides the overlay prompt.
 *
 * Only effective after calling showPrompt:inView:.
 * Does nothing if no prompt shown.
 *
 * @param isAnimated  whether to animate the prompt's exit procedure
 */
+ (void)hidePromptAnimated:(BOOL)isAnimated {
	if (promptView && promptLabel) {
		if (isAnimated) {
			// Animate the prompt upwards out of visibility
			[UIView beginAnimations:nil context:@"promptView"];
			[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
			[UIView setAnimationDuration:0.3];
			
			CGFloat shiftHeight;
			shiftHeight = (promptHeight == -1) ? -MSG_PROMPT_HEIGHT : -promptHeight;
			[promptView setFrame:CGRectMake(0, shiftHeight, 
											VIEW_WIDTH, MSG_PROMPT_HEIGHT)];
			[UIView commitAnimations];
		}
		
		// Free the prompt
		[promptLabel release];
		promptLabel = nil;
		[promptView release];
		promptView = nil;
	}
}

/**
 * Display an activity indicator pop-up.
 *
 * @param message  message of the activity indicator pop-up
 */
+ (void)displayActivityIndicatorWithMsg:(NSString*)message {
	if (progressView) {
		[progressView release];
	}
	progressView = [[[UIAlertView alloc] initWithTitle:message 
											   message:@""
											  delegate:nil 
									 cancelButtonTitle:nil 
									 otherButtonTitles:nil] autorelease];
	
	// Create a progress indicator inside the progress popup
	if (progressIndicator) {
		[progressIndicator release];
	}
	progressIndicator = [[UIActivityIndicatorView alloc] 
						 initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
	progressIndicator.center = CGPointMake(140, 120);
	[progressView addSubview:progressIndicator];
	
	// Display the progress popup
	[progressIndicator startAnimating];
	[progressView show];
}

/**
 * Hides the activity indicator pop-up.
 *
 * Does nothing if no activity indicator shown.
 */
+ (void)hideActivityIndicator {
	if (progressView && progressIndicator) {
		[progressView dismissWithClickedButtonIndex:0 animated:YES];
		[progressIndicator release];
		progressView = nil;
		progressIndicator = nil;
	}
}

/**
 * Display an alert pop-up.
 *
 * @param title    title of the alert pop-up
 * @param message  message of the alert pop-up
 */
+ (void)displayAlertWithTitle:(NSString*)title 
					  message:(NSString*)message {
	UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:title 
														 message:message 
														delegate:nil 
											   cancelButtonTitle:@"Okay" 
											   otherButtonTitles:nil] autorelease];
	[alertView show];
}

/**
 * Display a positionable alert pop-up.
 *
 * @param title    title of the alert pop-up
 * @param message  message of the alert pop-up
 * @param xShift   number of pixels to horizontally transform the pop-up
 * @param yShift   number of pixels to vertically transform the pop-up
 */
+ (void)displayShiftedAlertWithTitle:(NSString*)title 
							 message:(NSString*)message 
						  horizShift:(CGFloat)xShift 
						   vertShift:(CGFloat)yShift {
	UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:title 
														 message:message 
														delegate:nil 
											   cancelButtonTitle:@"Okay" 
											   otherButtonTitles:nil] autorelease];
	CGAffineTransform shiftTransform = CGAffineTransformMakeTranslation(xShift, yShift);
	[alertView setTransform:shiftTransform];
	[alertView show];
}

/**
 * Display a confirmation pop-up.
 *
 * @param title     title of the confirmation pop-up
 * @param message   message of the confirmation pop-up
 * @param tag       the tag identifier for the confirmation pop-up
 * @param delegate  delegate handling response to the confirmation pop-up
 */
+ (void)displayConfirmationWithTitle:(NSString*)title 
							 message:(NSString*)message 
								 tag:(NSUInteger)tag
							delegate:(id<UIAlertViewDelegate>)delegate {
	UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:title 
														 message:message 
														delegate:delegate 
											   cancelButtonTitle:@"Yes" 
											   otherButtonTitles:@"Cancel", nil] autorelease];
	[alertView setTag:tag];
	[alertView show];
}

/**
 * Create a UILabel resized to its text content.
 *
 * @param labelContent  the text to place in the label
 * @param font          the font type and size of the text
 * @param textColor     the color of the text
 * @param hPadding      horizontal padding on the left and right sides of the label
 * @param vPadding      vertical padding on the top and bottom sides of the label
 * @param height        height of the label
 * @return              a newly allocated UILabel with the specified text and style
 */
+ (UILabel*)getLabelResizedToText:(NSString*)labelContent 
							 font:(UIFont*)font 
						textColor:(UIColor*)textColor 
						 hPadding:(CGFloat)hPadding 
						 vPadding:(CGFloat)vPadding 
						   height:(CGFloat)height {
	CGRect labelFrame = CGRectMake(hPadding, vPadding, 
								   VIEW_WIDTH-hPadding*2, height-vPadding*2);
	UILabel* tempLabel = [[UILabel alloc] initWithFrame:labelFrame];
	
	// Set the label's text and properties
	tempLabel.text = labelContent;
	tempLabel.font = (font == nil) ? [UIFont systemFontOfSize:12.0] : font;
	tempLabel.textColor = (textColor == nil) ? [UIColor blackColor] : textColor;
	tempLabel.backgroundColor = [UIColor clearColor];
	tempLabel.numberOfLines = 0;
	tempLabel.lineBreakMode = UILineBreakModeWordWrap;
	
	// Resize the label to fit text
	CGRect frame = [tempLabel frame];
	CGSize size = [tempLabel.text sizeWithFont:tempLabel.font 
							 constrainedToSize:CGSizeMake(frame.size.width, CGFLOAT_MAX) 
								 lineBreakMode:UILineBreakModeWordWrap];
	
	frame.size.height = size.height;
	[tempLabel setFrame:frame];
	
	return tempLabel;
}

/**
 * Deallocate the graphics utilities.
 */
- (void)dealloc {
	if (promptView) {
		[promptView release], promptView = nil;
	}
	if (promptLabel) {
		[promptLabel release], promptLabel = nil;
	}
	if (progressView) {
		[progressView release], progressView = nil;
	}
	if (progressIndicator) {
		[progressIndicator release], progressIndicator = nil;
	}
	[sharedUtilities release], sharedUtilities = nil;
	[super dealloc];
}

@end
